package net.wicp.tams.common.apiext;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;

import lombok.extern.slf4j.Slf4j;
import net.wicp.tams.common.Conf;
import net.wicp.tams.common.constant.EPlatform;

@Slf4j
public class OSinfo {
	private static String OS = System.getProperty("os.name").toLowerCase();

	private static OSinfo _instance = new OSinfo();

	private EPlatform platform;

	private OSinfo() {
	}

	public static boolean isLinux() {
		return OS.indexOf("linux") >= 0;
	}

	public static boolean isMacOS() {
		return OS.indexOf("mac") >= 0 && OS.indexOf("os") > 0 && OS.indexOf("x") < 0;
	}

	public static boolean isMacOSX() {
		return OS.indexOf("mac") >= 0 && OS.indexOf("os") > 0 && OS.indexOf("x") > 0;
	}

	public static boolean isWindows() {
		return OS.indexOf("windows") >= 0;
	}

	public static boolean isOS2() {
		return OS.indexOf("os/2") >= 0;
	}

	public static boolean isSolaris() {
		return OS.indexOf("solaris") >= 0;
	}

	public static boolean isSunOS() {
		return OS.indexOf("sunos") >= 0;
	}

	public static boolean isMPEiX() {
		return OS.indexOf("mpe/ix") >= 0;
	}

	public static boolean isHPUX() {
		return OS.indexOf("hp-ux") >= 0;
	}

	public static boolean isAix() {
		return OS.indexOf("aix") >= 0;
	}

	public static boolean isOS390() {
		return OS.indexOf("os/390") >= 0;
	}

	public static boolean isFreeBSD() {
		return OS.indexOf("freebsd") >= 0;
	}

	public static boolean isIrix() {
		return OS.indexOf("irix") >= 0;
	}

	public static boolean isDigitalUnix() {
		return OS.indexOf("digital") >= 0 && OS.indexOf("unix") > 0;
	}

	public static boolean isNetWare() {
		return OS.indexOf("netware") >= 0;
	}

	public static boolean isOSF1() {
		return OS.indexOf("osf1") >= 0;
	}

	public static boolean isOpenVMS() {
		return OS.indexOf("openvms") >= 0;
	}

	/**
	 * 获取操作系统名字
	 * 
	 * @return 操作系统名
	 */
	public static EPlatform getOSname() {
		if (isAix()) {
			_instance.platform = EPlatform.AIX;
		} else if (isDigitalUnix()) {
			_instance.platform = EPlatform.Digital_Unix;
		} else if (isFreeBSD()) {
			_instance.platform = EPlatform.FreeBSD;
		} else if (isHPUX()) {
			_instance.platform = EPlatform.HP_UX;
		} else if (isIrix()) {
			_instance.platform = EPlatform.Irix;
		} else if (isLinux()) {
			_instance.platform = EPlatform.Linux;
		} else if (isMacOS()) {
			_instance.platform = EPlatform.Mac_OS;
		} else if (isMacOSX()) {
			_instance.platform = EPlatform.Mac_OS_X;
		} else if (isMPEiX()) {
			_instance.platform = EPlatform.MPEiX;
		} else if (isNetWare()) {
			_instance.platform = EPlatform.NetWare_411;
		} else if (isOpenVMS()) {
			_instance.platform = EPlatform.OpenVMS;
		} else if (isOS2()) {
			_instance.platform = EPlatform.OS2;
		} else if (isOS390()) {
			_instance.platform = EPlatform.OS390;
		} else if (isOSF1()) {
			_instance.platform = EPlatform.OSF1;
		} else if (isSolaris()) {
			_instance.platform = EPlatform.Solaris;
		} else if (isSunOS()) {
			_instance.platform = EPlatform.SunOS;
		} else if (isWindows()) {
			_instance.platform = EPlatform.Windows;
		} else {
			_instance.platform = EPlatform.Others;
		}
		return _instance.platform;
	}

	public static String findIpAddressTrue() {
		return StringUtil.isNull(Conf.get("common.apiext.os.ip")) ? findFirstNonLoopbackAddress().getHostAddress()
				: Conf.get("common.apiext.os.ip");
	}

	public static InetAddress findFirstNonLoopbackAddress() {
		InetAddress result = null;
		try {
			// 记录网卡最小索引
			int lowest = Integer.MAX_VALUE;
			// 获取所有网卡
			for (Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces(); nics
					.hasMoreElements();) {
				NetworkInterface ifc = nics.nextElement();
				if (ifc.isUp()) {
					log.trace("Testing interface: " + ifc.getDisplayName());
					if (ifc.getIndex() < lowest || result == null) {
						lowest = ifc.getIndex(); // 记录索引
					} else if (result != null) {
						continue;
					}

					// @formatter:off
					if (!ignoreInterface(ifc.getDisplayName())) { // 是否是被忽略的网卡
						for (Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements();) {
							InetAddress address = addrs.nextElement();
							if (address instanceof Inet4Address && !address.isLoopbackAddress()
									&& !ignoreAddress(address)) {
								log.trace("Found non-loopback interface: " + ifc.getDisplayName());
								result = address;
							}
						}
					}
					// @formatter:on
				}
			}
		} catch (IOException ex) {
			log.error("Cannot get first non-loopback address", ex);
		}

		if (result != null) {
			return result;
		}

		try {
			return InetAddress.getLocalHost(); // 如果以上逻辑都没有找到合适的网卡，则使用JDK的InetAddress.getLocalhost()
		} catch (UnknownHostException e) {
			log.warn("Unable to retrieve localhost");
		}

		return null;
	}

	private static boolean ignoreInterface(String interfaceName) {
		String macnames = Conf.get("common.apiext.os.ignore.mac");
		if (StringUtil.isNull(macnames)) {
			return false;
		}
		String[] macnameAry = macnames.split(",");
		for (String regex : macnameAry) {
			if (interfaceName.matches(regex)) {
				log.trace("Ignoring interface: " + interfaceName);
				return true;
			}
		}
		return false;
	}

	private static boolean ignoreAddress(InetAddress address) {
		String ips = Conf.get("common.apiext.os.ignore.ip");
		if (StringUtil.isNull(ips)) {
			return false;
		}
		String[] ipAry = ips.split(",");
		for (String regex : ipAry) {
			if (!address.getHostAddress().matches(regex) && !address.getHostAddress().startsWith(regex)) {
				log.trace("Ignoring address: " + address.getHostAddress());
				return true;
			}
		}
		return false;
	}
}
